home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume20 / rc / part03 < prev    next >
Encoding:
Text File  |  1991-05-22  |  50.6 KB  |  2,126 lines

  1. Newsgroups: comp.sources.misc
  2. From: Byron Rakitzis <byron@archone.tamu.edu>
  3. Subject:  v20i012:  rc - A Plan 9 shell reimplementation, Part03/04
  4. Message-ID: <1991May22.154305.3230@sparky.IMD.Sterling.COM>
  5. Date: Wed, 22 May 1991 15:43:05 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7. X-Md4-Signature: 5a48e4b485a61186a00b0e9d1cfb6138
  8.  
  9. Submitted-by: Byron Rakitzis <byron@archone.tamu.edu>
  10. Posting-number: Volume 20, Issue 12
  11. Archive-name: rc/part03
  12.  
  13. #! /bin/sh
  14. # This is a shell archive.  Remove anything before this line, then feed it
  15. # into a shell via "sh file" or similar.  To overwrite existing files,
  16. # type "sh file -c".
  17. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  18. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  19. # Contents:  CHANGES glob.c hash.c heredoc.c parse.y redir.c tree.c
  20. #   utils.c var.c which.c
  21. # Wrapped by kent@sparky on Wed May 22 01:21:49 1991
  22. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  23. echo If this archive is complete, you will see the following message:
  24. echo '          "shar: End of archive 3 (of 4)."'
  25. if test -f 'CHANGES' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'CHANGES'\"
  27. else
  28.   echo shar: Extracting \"'CHANGES'\" \(2395 characters\)
  29.   sed "s/^X//" >'CHANGES' <<'END_OF_FILE'
  30. XBugs and changes since version 0.9:
  31. X
  32. X-----
  33. XA pipe with a null first command caused rc to dump core. e.g.,
  34. X
  35. X    |;
  36. X-----
  37. XWhen fifo redirection was used with builtin commands, rc would hang:
  38. X
  39. X    diff <{echo hi} <{echo bye}
  40. X
  41. Xa missing exit() was the cause of all this
  42. X-----
  43. XA double backquote operator was added to make inlining of ifs-type material
  44. Xpossible; thus
  45. X
  46. X    `` ($ifs / :) command
  47. X
  48. Xis the same as
  49. X
  50. X    ifs=($ifs / :)
  51. X    ` command
  52. X
  53. Xonly without the assignment.
  54. X-----
  55. XAn "rc error" (e.g., trying to evaluate $()) inside a function messed up
  56. Xrc's interactive state, i.e., it stopped printing prompts.
  57. X
  58. X    fn foo { echo $() }
  59. X
  60. Xthis was fixed by adding full-fledged exception handling, with a separate
  61. Xexception stack
  62. X-----
  63. Xrc did not raise sigexit from the builtin "exit".
  64. X-----
  65. Xrc assumed the existence of getgroups(). Also, a typo in
  66. Xthe getgroups() code in which.c was fixed.
  67. X-----
  68. Xrc now sets $0 to the name of the function being called or the file being
  69. Xinterpreted by dot.
  70. X-----
  71. Xif - else statements were incorrectly exported into the environment
  72. X-----
  73. Xrc now has stubs for GNU readline compatability. (compile -DREADLINE)
  74. X-----
  75. Xrc used to use a single arena for temporary space which got clobbered if there
  76. Xwas a command of the form:
  77. X
  78. X    eval foo ; bar
  79. X
  80. Xsince the eval would cause rc to prematurely recycle that memory. I fixed
  81. Xthis by adding support for multiple arenas.
  82. X-----
  83. Xan assignment inside a compound command clobbered the global definition
  84. Xof a variable:
  85. X
  86. X    foo=a
  87. X    foo=b { stuff; foo=c; stuff }
  88. X
  89. X$foo was set to () after this.
  90. X-----
  91. Xrc -e now is much more sh-like. In particular
  92. X
  93. X    false || echo bletch
  94. X
  95. Xnow does the right thing.
  96. X-----
  97. Xrc did not print $prompt(2) while scanning heredocs
  98. X-----
  99. Xexec with a redirection but without other arguments now does the
  100. Xsame thing as sh, i.e., it alters rc's own file descriptors
  101. X-----
  102. Xthe command
  103. X
  104. X    eval eval eval [200 times or so] echo hi
  105. X
  106. Xwould cause rc to allocate obnoxious amounts of memory. This has
  107. Xbeen cleaned up.
  108. X-----
  109. Xrc how has full support for *all* signals, not just sigquit, sigint
  110. Xand sighup and sigterm. Additionally, the signal code is generated via
  111. Xan awk script operating on /usr/include/signal.h, so that rc "learns"
  112. Xabout the signals of a particular machine at compile time.
  113. X-----
  114. Xrc now supports "fn prompt", a function that gets executed before
  115. Xeach $prompt(1) is printed.
  116. X-----
  117. X~ () '' incorrectly returned a true status.
  118. X-----
  119. END_OF_FILE
  120.   if test 2395 -ne `wc -c <'CHANGES'`; then
  121.     echo shar: \"'CHANGES'\" unpacked with wrong size!
  122.   fi
  123.   # end of 'CHANGES'
  124. fi
  125. if test -f 'glob.c' -a "${1}" != "-c" ; then 
  126.   echo shar: Will not clobber existing file \"'glob.c'\"
  127. else
  128.   echo shar: Extracting \"'glob.c'\" \(6192 characters\)
  129.   sed "s/^X//" >'glob.c' <<'END_OF_FILE'
  130. X/* glob.c: rc's (ugly) globber. This code is not elegant, but it works */
  131. X
  132. X#include <sys/types.h>
  133. X#include "rc.h"
  134. X#include "glob.h"
  135. X#include "glom.h"
  136. X#include "nalloc.h"
  137. X#include "utils.h"
  138. X#include "match.h"
  139. X#include "footobar.h"
  140. X#include "list.h"
  141. X#ifdef NODIRENT
  142. X#include <sys/dir.h>
  143. X#define dirent direct /* need to get the struct declaraction right */
  144. X#else
  145. X#include <dirent.h>
  146. X#endif
  147. X
  148. Xstatic List *dmatch(char *, char *, char *);
  149. Xstatic List *doglob(char *, char *);
  150. Xstatic List *lglob(List *, char *, char *, SIZE_T);
  151. Xstatic List *sort(List *);
  152. X
  153. X/*
  154. X   matches a list of words s against a list of patterns p. Returns true iff
  155. X   a pattern in p matches a word in s. null matches null, but otherwise null
  156. X   patterns match nothing.
  157. X*/
  158. X
  159. Xboolean lmatch(List *s, List *p) {
  160. X    List *q;
  161. X    int i;
  162. X    boolean okay;
  163. X
  164. X    if (s == NULL) {
  165. X        if (p == NULL) /* null matches null */
  166. X            return TRUE;
  167. X        for (; p != NULL; p = p->n) { /* one or more stars match null */
  168. X            if (*p->w != '\0') { /* the null string is a special case; it does *not* match () */
  169. X                okay = TRUE;
  170. X                for (i = 0; p->w[i] != '\0'; i++)
  171. X                    if (p->w[i] != '*' || p->m[i] != 1) {
  172. X                        okay = FALSE;
  173. X                        break;
  174. X                    }
  175. X                if (okay)
  176. X                    return TRUE;
  177. X            }
  178. X        }
  179. X        return FALSE;
  180. X    }
  181. X
  182. X    for (; s != NULL; s = s->n)
  183. X        for (q = p; q != NULL; q = q->n)
  184. X            if (match(q->w, q->m, s->w))
  185. X                return TRUE;
  186. X    return FALSE;
  187. X}
  188. X
  189. X/* Matches a pattern p against the contents of directory d */
  190. X
  191. Xstatic List *dmatch(char *d, char *p, char *m) {
  192. X    boolean matched = FALSE;
  193. X    List *top, *r;
  194. X    DIR *dirp;
  195. X    struct dirent *dp;
  196. X    /* prototypes for XXXdir functions. comment out if necessary */
  197. X    extern DIR *opendir(const char *);
  198. X    extern struct dirent *readdir(DIR *);
  199. X    extern int closedir(DIR *);
  200. X
  201. X    if ((dirp = opendir(d)) == NULL)
  202. X        return NULL;
  203. X
  204. X    top = r = NULL;
  205. X
  206. X    while ((dp = readdir(dirp)) != NULL)
  207. X        if ((*dp->d_name != '.' || *p == '.') && match(p, m, dp->d_name)) { /* match ^. explicitly */
  208. X            matched = TRUE;
  209. X            if (top == NULL) {
  210. X                top = r = nnew(List);
  211. X            } else {
  212. X                r->n = nnew(List);
  213. X                r = r->n;
  214. X            }
  215. X            r->w = ncpy(dp->d_name);
  216. X            r->m = NULL;
  217. X        }
  218. X
  219. X    closedir(dirp);
  220. X
  221. X    if (!matched)
  222. X        return NULL;
  223. X
  224. X    r->n = NULL;
  225. X    return top;
  226. X}
  227. X
  228. X/*
  229. X   lglob() globs a pattern agains a list of directory roots. e.g., (/tmp /usr /bin) "*"
  230. X   will return a list with all the files in /tmp, /usr, and /bin. NULL on no match.
  231. X   slashcount indicates the number of slashes to stick between the directory and the
  232. X   matched name. e.g., for matching ////tmp/////foo*
  233. X*/
  234. X
  235. Xstatic List *lglob(List *s, char *p, char *m, SIZE_T slashcount) {
  236. X    List *q, *r, *top, foo;
  237. X    static List slash;
  238. X    static SIZE_T slashsize = 0;
  239. X
  240. X    if (slashcount + 1 > slashsize) {
  241. X        slash.w = ealloc(slashcount + 1);
  242. X        slashsize = slashcount;
  243. X    }
  244. X    slash.w[slashcount] = '\0';
  245. X    while (slashcount > 0)
  246. X        slash.w[--slashcount] = '/';
  247. X
  248. X    for (top = r = NULL; s != NULL; s = s->n) {
  249. X        q = dmatch(s->w, p, m);
  250. X        if (q != NULL) {
  251. X            foo.w = s->w;
  252. X            foo.m = NULL;
  253. X            foo.n = NULL;
  254. X            if (!(s->w[0] == '/' && s->w[1] == '\0')) /* need to separate */
  255. X                q = concat(&slash, q);          /* dir/name with slash */
  256. X            q = concat(&foo, q);
  257. X            if (r == NULL)
  258. X                top = r = q;
  259. X            else
  260. X                r->n = q;
  261. X            while (r->n != NULL)
  262. X                r = r->n;
  263. X        }
  264. X    }
  265. X    return top;
  266. X}
  267. X
  268. X/*
  269. X   Doglob globs a pathname in pattern form against a unix path. Returns the original
  270. X   pattern (cleaned of metacharacters) on failure, or the globbed string(s).
  271. X*/
  272. X
  273. Xstatic List *doglob(char *w, char *m) {
  274. X    static char *dir = NULL, *pattern = NULL, *metadir = NULL, *metapattern = NULL;
  275. X    static SIZE_T dsize = 0;
  276. X    char *d, *p, *md, *mp;
  277. X    SIZE_T psize;
  278. X    char *s = w;
  279. X    List firstdir;
  280. X    List *matched;
  281. X    int slashcount;
  282. X
  283. X    if ((psize = strlen(w) + 1) > dsize || dir == NULL) {
  284. X        efree(dir); efree(pattern); efree(metadir); efree(metapattern);
  285. X        dir = ealloc(psize);
  286. X        pattern = ealloc(psize);
  287. X        metadir = ealloc(psize);
  288. X        metapattern = ealloc(psize);
  289. X        dsize = psize;
  290. X    }
  291. X
  292. X    d = dir;
  293. X    p = pattern;
  294. X    md = metadir;
  295. X    mp = metapattern;
  296. X
  297. X    if (*s == '/') {
  298. X        while (*s == '/')
  299. X            *d++ = *s++, *md++ = *m++;
  300. X    } else {
  301. X        while (*s != '/' && *s != '\0')
  302. X            *d++ = *s++, *md++ = *m++; /* get first directory component */
  303. X    }
  304. X    *d = '\0';
  305. X
  306. X    /*
  307. X       Special case: no slashes in the pattern, i.e., open the current directory.
  308. X       Remember that w cannot consist of slashes alone (the other way *s could be
  309. X       zero) since doglob gets called iff there's a metacharacter to be matched
  310. X    */
  311. X    if (*s == '\0') {
  312. X        matched = dmatch(".", dir, metadir);
  313. X        goto end;
  314. X    }
  315. X
  316. X    if (*w == '/') {
  317. X        firstdir.w = dir;
  318. X        firstdir.m = metadir;
  319. X        firstdir.n = NULL;
  320. X        matched = &firstdir;
  321. X    } else {
  322. X        /*
  323. X           we must glob against current directory,
  324. X           since the first character is not a slash.
  325. X        */
  326. X        matched = dmatch(".", dir, metadir);
  327. X    }
  328. X
  329. X    do {
  330. X        for (slashcount = 0; *s == '/'; s++, m++)
  331. X            slashcount++; /* skip slashes */
  332. X
  333. X        while (*s != '/' && *s != '\0')
  334. X            *p++ = *s++, *mp++ = *m++; /* get pattern */
  335. X        *p = '\0';
  336. X
  337. X        matched = lglob(matched, pattern, metapattern, slashcount);
  338. X
  339. X        p = pattern, mp = metapattern;
  340. X    } while (*s != '\0');
  341. X
  342. Xend:    if (matched == NULL) {
  343. X        matched = nnew(List);
  344. X        matched->w = w;
  345. X        matched->m = NULL;
  346. X        matched->n = NULL;
  347. X    }
  348. X    return matched;
  349. X}
  350. X
  351. X/*
  352. X   Globs a list; checks to see if each element in the list has a metacharacter. If it
  353. X   does, it is globbed, and the output is sorted.
  354. X*/
  355. X
  356. XList *glob(List *s) {
  357. X    List *top, *r;
  358. X    boolean meta;
  359. X
  360. X    for (r = s, meta = FALSE; r != NULL; r = r->n)
  361. X        if (r->m != NULL)
  362. X            meta = TRUE;
  363. X
  364. X    if (!meta)
  365. X        return s; /* don't copy lists with no metacharacters in them */
  366. X
  367. X    for (top = r = NULL; s != NULL; s = s->n) {
  368. X        if (s->m == NULL) { /* no metacharacters; just tack on to the return list */
  369. X            if (top == NULL) {
  370. X                top = r = nnew(List);
  371. X            } else {
  372. X                r->n = nnew(List);
  373. X                r = r->n;
  374. X            }
  375. X            r->w = s->w;
  376. X        } else {
  377. X            if (top == NULL)
  378. X                top = r = sort(doglob(s->w, s->m));
  379. X            else
  380. X                r->n = sort(doglob(s->w, s->m));
  381. X            while (r->n != NULL)
  382. X                r = r->n;
  383. X        }
  384. X    }
  385. X
  386. X    r->n = NULL;
  387. X    return top;
  388. X}
  389. X
  390. Xstatic List *sort(List *s) {
  391. X    SIZE_T nel = listnel(s);
  392. X
  393. X    if (nel > 1) {
  394. X        char **a;
  395. X        List *t;
  396. X
  397. X        qsort(a = list2array(s, FALSE), nel, sizeof(char *), starstrcmp);
  398. X
  399. X        for (t = s; t != NULL; t = t->n)
  400. X            t->w = *a++;
  401. X    }
  402. X
  403. X    return s;
  404. X}
  405. END_OF_FILE
  406.   if test 6192 -ne `wc -c <'glob.c'`; then
  407.     echo shar: \"'glob.c'\" unpacked with wrong size!
  408.   fi
  409.   # end of 'glob.c'
  410. fi
  411. if test -f 'hash.c' -a "${1}" != "-c" ; then 
  412.   echo shar: Will not clobber existing file \"'hash.c'\"
  413. else
  414.   echo shar: Extracting \"'hash.c'\" \(6588 characters\)
  415.   sed "s/^X//" >'hash.c' <<'END_OF_FILE'
  416. X/* hash.c: hash table support for functions and variables. */
  417. X
  418. X/*
  419. X   functions and variables are cached in both internal and external
  420. X   form for performance. Thus a variable which is never "dereferenced"
  421. X   with a $ is passed on to rc's children untouched. This is not so
  422. X   important for variables, but is a big win for functions, where a call
  423. X   to yyparse() is involved.
  424. X*/
  425. X
  426. X#include "rc.h"
  427. X#include "utils.h"
  428. X#include "hash.h"
  429. X#include "list.h"
  430. X#include "tree.h"
  431. X#include "footobar.h"
  432. X
  433. Xstatic boolean exportable(char *);
  434. Xstatic int hash(char *, int);
  435. Xstatic int find(char *, Htab *, int);
  436. Xstatic void free_fn(Function *);
  437. X
  438. XHtab *fp;
  439. XHtab *vp;
  440. Xstatic int fused, fsize, vused, vsize;
  441. Xstatic char **env;
  442. Xstatic int bozosize;
  443. Xstatic int envsize;
  444. Xstatic boolean env_dirty = TRUE;
  445. Xstatic char *dead = "";
  446. X
  447. X#define HASHSIZE 64 /* rc was debugged with HASHSIZE == 2; 64 is about right for normal use */
  448. X
  449. Xvoid inithash(void) {
  450. X    int i;
  451. X    Htab *fpp, *vpp;
  452. X
  453. X    fp = ealloc(sizeof(Htab) * HASHSIZE);
  454. X    vp = ealloc(sizeof(Htab) * HASHSIZE);
  455. X    fused = vused = 0;
  456. X    fsize = vsize = HASHSIZE;
  457. X
  458. X    for (vpp = vp, fpp = fp, i = 0; i < HASHSIZE; i++, vpp++, fpp++)
  459. X        vpp->name = fpp->name = NULL;
  460. X}
  461. X
  462. X#define ADV()   {if ((c = *s++) == '\0') break;}
  463. X
  464. X/* hash function courtesy of paul haahr */
  465. X
  466. Xstatic int hash(char *s, int size) {
  467. X    int n = 0;
  468. X    int c;
  469. X
  470. X    while (1) {
  471. X        ADV();
  472. X        n += (c << 17) ^ (c << 11) ^ (c << 5) ^ (c >> 1);
  473. X        ADV();
  474. X        n ^= (c << 14) + (c << 7) + (c << 4) + c;
  475. X        ADV();
  476. X        n ^= (~c << 11) | ((c << 3) ^ (c >> 1));
  477. X        ADV();
  478. X        n -= (c << 16) | (c << 9) | (c << 2) | (c & 3);
  479. X    }
  480. X
  481. X    if (n < 0)
  482. X        n = ~n;
  483. X
  484. X    return n & (size - 1); /* need power of 2 size */
  485. X}
  486. X
  487. Xstatic boolean rehash(Htab *ht) {
  488. X    int i,j,size;
  489. X    int newsize,newused;
  490. X    Htab *newhtab;
  491. X
  492. X    if (ht == fp) {
  493. X        if (fsize > 2 * fused)
  494. X            return FALSE;
  495. X        size = fsize;
  496. X    } else {
  497. X        if (vsize > 2 * vused)
  498. X            return FALSE;
  499. X        size = vsize;
  500. X    }
  501. X
  502. X
  503. X    newsize = 2 * size;
  504. X    newhtab = ealloc(newsize * sizeof(Htab));
  505. X    for (i = 0; i < newsize; i++)
  506. X        newhtab[i].name = NULL;
  507. X
  508. X    for (i = newused = 0; i < size; i++)
  509. X        if (ht[i].name != NULL && ht[i].name != dead) {
  510. X            newused++;
  511. X            j = hash(ht[i].name, newsize);
  512. X            while (newhtab[j].name != NULL) {
  513. X                j++;
  514. X                j &= (newsize - 1);
  515. X            }
  516. X            newhtab[j].name = ht[i].name;
  517. X            newhtab[j].p = ht[i].p;
  518. X        }
  519. X
  520. X    if (ht == fp) {
  521. X        fused = newused;
  522. X        fp = newhtab;
  523. X        fsize = newsize;
  524. X    } else {
  525. X        vused = newused;
  526. X        vp = newhtab;
  527. X        vsize = newsize;
  528. X    }
  529. X
  530. X    efree(ht);
  531. X    return TRUE;
  532. X}
  533. X
  534. X#define varfind(s) find(s,vp,vsize)
  535. X#define fnfind(s) find(s,fp,fsize)
  536. X
  537. Xstatic int find(char *s, Htab *ht, int size) {
  538. X    int h = hash(s, size);
  539. X
  540. X    while (ht[h].name != NULL && !streq(ht[h].name,s)) {
  541. X        h++;
  542. X        h &= size - 1;
  543. X    }
  544. X
  545. X    return h;
  546. X}
  547. X
  548. Xvoid *lookup(char *s, Htab *ht) {
  549. X    int h = find(s, ht, ht == fp ? fsize : vsize);
  550. X
  551. X    return (ht[h].name == NULL) ? NULL : ht[h].p;
  552. X}
  553. X
  554. XFunction *get_fn_place(char *s) {
  555. X    int h = fnfind(s);
  556. X
  557. X    env_dirty = TRUE;
  558. X
  559. X    if (fp[h].name == NULL) {
  560. X        if (rehash(fp))
  561. X            h = fnfind(s);
  562. X        fused++;
  563. X        fp[h].name = ecpy(s);
  564. X        fp[h].p = enew(Function);
  565. X    } else
  566. X        free_fn(fp[h].p);
  567. X
  568. X    return fp[h].p;
  569. X}
  570. X
  571. XVariable *get_var_place(char *s, boolean stack) {
  572. X    Variable *new;
  573. X    int h = varfind(s);
  574. X
  575. X    env_dirty = TRUE;
  576. X
  577. X    if (vp[h].name == NULL) {
  578. X        if (rehash(vp))
  579. X            h = varfind(s);
  580. X        vused++;
  581. X        vp[h].name = ecpy(s);
  582. X        strcpy(vp[h].name, s);
  583. X        vp[h].p = enew(Variable);
  584. X        ((Variable *)vp[h].p)->n = NULL;
  585. X        return vp[h].p;
  586. X    } else {
  587. X        if (stack) {    /* increase the stack by 1 */
  588. X            new = enew(Variable);
  589. X            new->n = vp[h].p;
  590. X            return vp[h].p = new;
  591. X        } else {    /* trample the top of the stack */
  592. X            new = vp[h].p;
  593. X            efree(new->extdef);
  594. X            listfree(new->def);
  595. X            return new;
  596. X        }
  597. X    }
  598. X}
  599. X
  600. Xvoid delete_fn(char *s) {
  601. X    int h = fnfind(s);
  602. X
  603. X    if (fp[h].name == NULL)
  604. X        return; /* not found */
  605. X
  606. X    env_dirty = TRUE;
  607. X
  608. X    free_fn(fp[h].p);
  609. X    efree(fp[h].p);
  610. X    efree(fp[h].name);
  611. X    if (fp[h+1].name == NULL) {
  612. X        --fused;
  613. X        fp[h].name = NULL;
  614. X    } else {
  615. X        fp[h].name = dead;
  616. X    }
  617. X}
  618. X
  619. Xvoid delete_var(char *s, boolean stack) {
  620. X    int h = varfind(s);
  621. X    Variable *v;
  622. X
  623. X    if (vp[h].name == NULL)
  624. X        return; /* not found */
  625. X
  626. X    env_dirty = TRUE;
  627. X
  628. X    v = vp[h].p;
  629. X    efree(v->extdef);
  630. X    listfree(v->def);
  631. X
  632. X    if (v->n != NULL) { /* This is the top of a stack */
  633. X        if (stack) { /* pop */
  634. X            vp[h].p = v->n;
  635. X            efree(v);
  636. X        } else { /* else just empty */
  637. X            v->extdef = NULL;
  638. X            v->def = NULL;
  639. X        }
  640. X    } else { /* needs to be removed from the hash table */
  641. X        efree(v);
  642. X        efree(vp[h].name);
  643. X        if (vp[h+1].name == NULL) {
  644. X            --vused;
  645. X            vp[h].name = NULL;
  646. X        } else {
  647. X            vp[h].name = dead;
  648. X        }
  649. X    }
  650. X}
  651. X
  652. Xstatic void free_fn(Function *f) {
  653. X    treefree(f->def);
  654. X    efree(f->extdef);
  655. X}
  656. X
  657. Xvoid initenv(char **envp) {
  658. X    int n;
  659. X
  660. X    for (n = 0; envp[n] != NULL; n++)
  661. X        ;
  662. X    n++; /* one for the null terminator */
  663. X
  664. X    if (n < HASHSIZE)
  665. X        n = HASHSIZE;
  666. X
  667. X    env = ealloc((envsize = 2 * n) * sizeof (char *));
  668. X
  669. X    for (; *envp != NULL; envp++)
  670. X        if (strncmp(*envp, "fn_", sizeof("fn_") - 1) == 0)
  671. X            fnassign_string(*envp);
  672. X        else
  673. X            if (!varassign_string(*envp)) /* add to bozo env */
  674. X                env[bozosize++] = *envp;
  675. X}
  676. X
  677. Xstatic boolean exportable(char *s) {
  678. X    int i;
  679. X    static char *notforexport[] = {
  680. X        "sighup", "sigint", "sigquit", "sigterm", "sigexit",
  681. X        "apid", "pid", "apid", "*", "ifs"
  682. X    };
  683. X
  684. X    for (i = 0; i < arraysize(notforexport); i++)
  685. X        if (streq(s,notforexport[i]))
  686. X            return FALSE;
  687. X    return TRUE;
  688. X}
  689. X
  690. Xchar **makeenv(void) {
  691. X    int ep, i;
  692. X    char *v;
  693. X
  694. X    if (!env_dirty)
  695. X        return env;
  696. X
  697. X    env_dirty = FALSE;
  698. X    ep = bozosize;
  699. X
  700. X    if (vsize + fsize + 1 + bozosize > envsize) {
  701. X        envsize = 2 * (bozosize + vsize + fsize + 1);
  702. X        env = erealloc(env, envsize * sizeof(char *));
  703. X    }
  704. X
  705. X    for (i = 0; i < vsize; i++) {
  706. X        if (vp[i].name == NULL || !exportable(vp[i].name))
  707. X            continue;
  708. X        v = varlookup_string(vp[i].name);
  709. X        if (v != NULL)
  710. X            env[ep++] = v;
  711. X    }
  712. X    for (i = 0; i < fsize; i++) {
  713. X        if (fp[i].name == NULL || !exportable(fp[i].name))
  714. X            continue;
  715. X        env[ep++] = fnlookup_string(fp[i].name);
  716. X    }
  717. X    env[ep] = NULL;
  718. X    return env;
  719. X}
  720. X
  721. Xvoid whatare_all_vars(void) {
  722. X    int i;
  723. X    List *s,*t;
  724. X
  725. X    for (i = 0; i < vsize; i++)
  726. X        if (vp[i].name != NULL && (s = varlookup(vp[i].name)) != NULL) {
  727. X            fprint(1,"%s=%s", vp[i].name, (s->n == NULL ? "" : "("));
  728. X            for (t = s; t->n != NULL; t = t->n)
  729. X                fprint(1,"%s ",strprint(t->w, FALSE, TRUE));
  730. X            fprint(1,"%s%s\n",strprint(t->w, FALSE, TRUE), (s->n == NULL ? "" : ")"));
  731. X        }
  732. X    for (i = 0; i < fsize; i++)
  733. X        if (fp[i].name != NULL)
  734. X            fprint(1,"fn %s {%s}\n", fp[i].name, ptree(fnlookup(fp[i].name)));
  735. X}
  736. X
  737. X/* fake getenv() for readline() follows: */
  738. X
  739. X#ifdef READLINE
  740. Xchar *getenv(char *name) {
  741. X    List *s;
  742. X
  743. X    if (name == NULL || (s = varlookup(name)) == NULL)
  744. X        return NULL;
  745. X
  746. X    return s->w;
  747. X}
  748. X#endif
  749. X
  750. END_OF_FILE
  751.   if test 6588 -ne `wc -c <'hash.c'`; then
  752.     echo shar: \"'hash.c'\" unpacked with wrong size!
  753.   fi
  754.   # end of 'hash.c'
  755. fi
  756. if test -f 'heredoc.c' -a "${1}" != "-c" ; then 
  757.   echo shar: Will not clobber existing file \"'heredoc.c'\"
  758. else
  759.   echo shar: Extracting \"'heredoc.c'\" \(3252 characters\)
  760.   sed "s/^X//" >'heredoc.c' <<'END_OF_FILE'
  761. X/* heredoc.c: heredoc slurping is done here */
  762. X
  763. X#include "rc.h"
  764. X#include "lex.h"
  765. X#include "utils.h"
  766. X#include "nalloc.h"
  767. X#include "heredoc.h"
  768. X#include "tree.h"
  769. X#include "input.h"
  770. X#include "hash.h"
  771. X#include "glom.h"
  772. X
  773. Xstruct Hq {
  774. X    Node *doc;
  775. X    char *name;
  776. X    Hq *n;
  777. X} *hq;
  778. X
  779. Xstatic SIZE_T j, bufsize;
  780. X
  781. X/* a stupid realloc for nalloc */
  782. X
  783. Xstatic char *renalloc(char *buf, SIZE_T n) {
  784. X
  785. X    while (n >= bufsize - 2)
  786. X        bufsize *= 2;
  787. X
  788. X    return memcpy(nalloc(bufsize), buf, j);
  789. X}
  790. X
  791. X/*
  792. X   read in a heredocument. A clever trick: skip over any partially matched end-of-file
  793. X   marker storing only the number of characters matched. If the whole marker is matched,
  794. X   return from readheredoc(). If only part of the marker is matched, copy that part into
  795. X   the heredocument.
  796. X*/
  797. X
  798. Xstatic char *readheredoc(char *eof) {
  799. X    int c;
  800. X    SIZE_T i, markerlen, varsize = 0;
  801. X    char *buf, *varname = NULL, *newvarname;
  802. X    boolean quoted = FALSE;
  803. X    List *var;
  804. X
  805. X    if (*eof == '\'') {
  806. X        quoted = TRUE;
  807. X        eof++;
  808. X    }
  809. X
  810. X    markerlen = strlen(eof);
  811. X
  812. X    buf = nalloc(bufsize = 512);
  813. X    j = 0;
  814. X
  815. X    while (1) {
  816. X        print_prompt2();
  817. X
  818. X        for (i = 0, c = gchar(); eof[i] == c && i < markerlen; i++) /* match the eof marker */
  819. X            c = gchar();
  820. X
  821. X        if (i == markerlen && c == '\n') { /* if the whole marker was matched, return */
  822. X            buf[j] = 0;
  823. X            return buf;
  824. X        }
  825. X
  826. X        if (i > 0) { /* else copy the partially matched marker into the heredocument */
  827. X            if (i + j >= bufsize - 2)
  828. X                buf = renalloc(buf, i + j);
  829. X            memcpy(buf + j, eof, i);
  830. X            j += i;
  831. X        }
  832. X
  833. X        for (; c != '\n'; c = gchar()) {
  834. X            if (c == EOF)
  835. X                scanerror("EOF inside heredoc");
  836. X            if (j >= bufsize - 2)
  837. X                buf = renalloc(buf, j);
  838. X            if (quoted || c != '$') {
  839. X                buf[j++] = c;
  840. X                continue; /* avoid an extra level of indentation */
  841. X            }
  842. X            if ((c = gchar()) == '$' || dnw[c]) {
  843. X                if (c != '$') /* $$ quotes $, but $<nonalnum> is transcribed literally */
  844. X                    buf[j++] = '$';
  845. X                buf[j++] = c;
  846. X            } else {
  847. X                if (varsize == 0)
  848. X                    varname = nalloc(varsize = 16);
  849. X                for (i = 0; !dnw[c]; i++, c = gchar()) {
  850. X                    if (i >= varsize - 1) {
  851. X                        newvarname = nalloc(varsize *= 4);
  852. X                        memcpy(newvarname, varname, i);
  853. X                        varname = newvarname;
  854. X                    }
  855. X                    varname[i] = c;
  856. X                }
  857. X                varname[i] = '\0';
  858. X                if (c != '^')
  859. X                    ugchar(c);
  860. X                var = varlookup(varname);
  861. X                if (varname[0] == '*' && varname[1] == '\0') /* skip $0 */
  862. X                    var = var->n;
  863. X                if ((var = flatten(var)) != NULL) {
  864. X                    i = strlen(var->w);
  865. X                    while (j + i >= bufsize - 2)
  866. X                        buf = renalloc(buf, i + j);
  867. X                    memcpy(buf + j, var->w, i);
  868. X                    j += i;
  869. X                }
  870. X            }
  871. X        }
  872. X        buf[j++] = c;
  873. X    }
  874. X}
  875. X
  876. X/* read in heredocs when yyparse hits a newline. called from yyparse */
  877. X
  878. Xvoid heredoc(int end) {
  879. X    if (end && hq != NULL)
  880. X        rc_error("EOF on command line with heredoc");
  881. X
  882. X    for (; hq != NULL; hq = hq->n) {
  883. X        hq->doc->u[0].i = HERESTRING;
  884. X        hq->doc->u[2].p = newnode(rWORD,readheredoc(hq->name), NULL);
  885. X    }
  886. X}
  887. X
  888. X/* queue pending heredocs into a queue. called from yyparse */
  889. X
  890. Xvoid qdoc(Node *name, Node *n) {
  891. X    Hq *new;
  892. X
  893. X    if (name->type != rWORD)
  894. X        scanerror("eof-marker must be a single word");
  895. X
  896. X    if (hq == NULL) {
  897. X        new = hq = nnew(Hq);
  898. X    } else {
  899. X        for (new = hq; new->n != NULL; new = new->n)
  900. X            ;
  901. X        new->n = nnew(Hq);
  902. X        new = new->n;
  903. X    }
  904. X
  905. X    new->name = name->u[0].s;
  906. X    new->doc = n;
  907. X    new->n = NULL;
  908. X}
  909. END_OF_FILE
  910.   if test 3252 -ne `wc -c <'heredoc.c'`; then
  911.     echo shar: \"'heredoc.c'\" unpacked with wrong size!
  912.   fi
  913.   # end of 'heredoc.c'
  914. fi
  915. if test -f 'parse.y' -a "${1}" != "-c" ; then 
  916.   echo shar: Will not clobber existing file \"'parse.y'\"
  917. else
  918.   echo shar: Extracting \"'parse.y'\" \(5173 characters\)
  919.   sed "s/^X//" >'parse.y' <<'END_OF_FILE'
  920. X/* parse.y */
  921. X
  922. X/*
  923. X * Adapted from rc grammar, v10 manuals, volume 2.
  924. X */
  925. X
  926. X%{
  927. X#include "stddef.h"
  928. X#include "node.h"
  929. X#include "lex.h"
  930. X#include "tree.h"
  931. X#include "heredoc.h"
  932. X#include "parse.h"
  933. X#include "utils.h"
  934. X#undef NULL
  935. X#define NULL 0
  936. X#undef lint
  937. X#define lint        /* hush up gcc -Wall, leave out the dumb sccsid's. */
  938. Xstatic Node *star, *nolist;
  939. XNode *parsetree;    /* not using yylval because bison declares it as an auto */
  940. X%}
  941. X
  942. X%term BANG DUP ELSE END FN FOR HUH IF IN LBRACK PIPE RBRACK
  943. X%term REDIR STAR SUB SUBSHELL SWITCH TWIDDLE WHILE WORD
  944. X
  945. X%left IF WHILE FOR SWITCH ')' ELSE
  946. X%left ANDAND OROR
  947. X%left BANG SUBSHELL
  948. X%left PIPE
  949. X%left '^'
  950. X%right '$' COUNT FLAT
  951. X%left SUB
  952. X%left '`' BACKBACK
  953. X
  954. X%union {
  955. X    struct Node *node;
  956. X    struct Redir redir;
  957. X    struct Pipe pipe;
  958. X    struct Dup dup;
  959. X    struct Word word;
  960. X    char *keyword;
  961. X}
  962. X
  963. X%type <redir> REDIR
  964. X%type <pipe> PIPE
  965. X%type <dup> DUP
  966. X%type <word> WORD
  967. X%type <keyword> keyword
  968. X%type <node> assign body brace cmd cmdsa cmdsan comword epilog
  969. X         first line paren redir simple iftail word words
  970. X
  971. X%start rc
  972. X
  973. X%%
  974. X
  975. Xrc    : line end        { parsetree = $1; return 1; }
  976. X    | error end        { yyerrok; parsetree = NULL; return -1; }
  977. X
  978. X/* an rc line may end in end-of-file as well as newline, e.g., rc -c 'ls' */
  979. Xend    : END    /* EOF */    { heredoc(1); } /* flag error if there is a heredoc in the queue */
  980. X    | '\n'            { heredoc(0); } /* get heredoc on \n */
  981. X
  982. X/* a cmdsa is a command followed by ampersand or newline (used in "line" and "body") */
  983. Xcmdsa    : cmd ';'
  984. X    | cmd '&'        { $$ = ($1 != NULL ? newnode(NOWAIT,$1) : $1); }
  985. X
  986. X/* a line is a single command, or a command terminated by ; or & followed by a line (recursive) */
  987. Xline    : cmd
  988. X    | cmdsa line        { $$ = ($1 != NULL ? newnode(BODY,$1,$2) : $2); }
  989. X
  990. X/* a body is like a line, only commands may also be terminated by newline */
  991. Xbody    : cmd
  992. X    | cmdsan body        { $$ = ($1 != NULL ? newnode(BODY,$1,$2) : $2); }
  993. X
  994. Xcmdsan    : cmdsa
  995. X    | cmd '\n'        { $$ = $1; heredoc(0); } /* get h.d. on \n */
  996. X
  997. Xbrace    : '{' body '}'        { $$ = $2; }
  998. X
  999. Xparen    : '(' body ')'        { $$ = $2; }
  1000. X
  1001. Xassign    : first '=' word    { $$ = newnode(ASSIGN,$1,$3); }
  1002. X
  1003. Xepilog    :            { $$ = NULL; }
  1004. X    | redir epilog        { $$ = newnode(EPILOG,$1,$2); }
  1005. X
  1006. X/* a redirection is a dup (e.g., >[1=2]) or a file redirection. (e.g., > /dev/null) */
  1007. Xredir    : DUP            { $$ = newnode(rDUP,$1.type,$1.left,$1.right); }
  1008. X    | REDIR word        { $$ = newnode(rREDIR,$1.type,$1.fd,$2);
  1009. X                  if ($1.type == HEREDOC) qdoc($2, $$); /* queue heredocs up */
  1010. X                }
  1011. X
  1012. X/* the tail of an if statement can be a command, or a braced command followed by else on the same line */
  1013. Xiftail    : cmd %prec IF
  1014. X    | brace ELSE cmd    { $$ = newnode(rELSE,$1,$3); }
  1015. X
  1016. X/* skipnl() skips newlines and comments between an operator and its operand */
  1017. Xcmd    :                        { $$ = NULL; }
  1018. X    | simple
  1019. X    | brace epilog                    { $$ = ($2 == NULL ? $1 : newnode(BRACE,$1,$2)); }
  1020. X    | IF paren { skipnl(); } iftail            { $$ = newnode(rIF,$2,$4); }
  1021. X    | FOR '(' word IN words ')' { skipnl(); } cmd    { $$ = newnode(FORIN,$3,$5,$8); }
  1022. X    | FOR '(' word ')' { skipnl(); } cmd        { $$ = newnode(FORIN,$3,star,$6); }
  1023. X    | WHILE paren { skipnl(); } cmd            { $$ = newnode(rWHILE,$2,$4); }
  1024. X    | SWITCH '(' word ')' { skipnl(); } brace    { $$ = newnode(rSWITCH,$3,$6); }
  1025. X    | TWIDDLE word words                { $$ = newnode(MATCH,$2,$3); }
  1026. X    | cmd ANDAND { skipnl(); } cmd            { $$ = ($1 != NULL ? newnode(rANDAND,$1,$4) : $4); }
  1027. X    | cmd OROR { skipnl(); } cmd            { $$ = ($1 != NULL ? newnode(rOROR,$1,$4) : $4); }
  1028. X     | cmd PIPE { skipnl(); } cmd            { $$ = newnode(rPIPE,$2.left,$2.right,$1,$4); }
  1029. X    | redir cmd %prec BANG                { $$ = ($2 != NULL ? newnode(PRE,$1,$2) : $1); }
  1030. X    | assign cmd %prec BANG                { $$ = ($2 != NULL ? newnode(PRE,$1,$2) : $1); }
  1031. X    | BANG cmd                    { $$ = newnode(rBANG,$2); }
  1032. X    | SUBSHELL cmd                    { $$ = newnode(rSUBSHELL,$2); }
  1033. X    | FN words brace                { $$ = newnode(NEWFN,$2,$3); }
  1034. X    | FN words                    { $$ = newnode(RMFN,$2); }
  1035. X
  1036. Xsimple    : first
  1037. X    | simple word            { $$ = ($2 != NULL ? newnode(ARGS,$1,$2) : $1); }
  1038. X    | simple redir            { $$ = newnode(ARGS,$1,$2); }
  1039. X
  1040. Xfirst    : comword
  1041. X    | first '^' word        { $$ = newnode(CONCAT,$1,$3); }
  1042. X
  1043. Xword    : comword
  1044. X    | keyword            { $$ = newnode(rWORD,$1, NULL); }
  1045. X    | word '^' word            { $$ = newnode(CONCAT,$1,$3); }
  1046. X
  1047. Xcomword    : '$' word            { $$ = newnode(VAR,$2); }
  1048. X    | '$' word SUB words ')'    { $$ = newnode(VARSUB,$2,$4); }
  1049. X    | COUNT word            { $$ = newnode(rCOUNT,$2); }
  1050. X    | FLAT word            { $$ = newnode(rFLAT, $2); }
  1051. X    | WORD                { $$ = newnode(rWORD,$1.w, $1.m); }
  1052. X    | '`' word            { $$ = newnode(BACKQ,nolist,$2); }
  1053. X    | '`' brace            { $$ = newnode(BACKQ,nolist,$2); }
  1054. X    | BACKBACK word    brace        { $$ = newnode(BACKQ,$2,$3); }
  1055. X    | BACKBACK word    word        { $$ = newnode(BACKQ,$2,$3); }
  1056. X    | '(' words ')'            { $$ = $2; }
  1057. X    | REDIR brace            { $$ = newnode(NMPIPE,$1.type,$1.fd,$2); }
  1058. X
  1059. Xkeyword    : FOR        { $$ = "for"; }
  1060. X    | IN        { $$ = "in"; }
  1061. X    | WHILE        { $$ = "while"; }
  1062. X    | IF        { $$ = "if"; }
  1063. X    | SWITCH    { $$ = "switch"; }
  1064. X    | FN        { $$ = "fn"; }
  1065. X    | ELSE        { $$ = "else"; }
  1066. X    | TWIDDLE    { $$ = "~"; }
  1067. X    | BANG        { $$ = "!"; }
  1068. X    | SUBSHELL    { $$ = "@"; }
  1069. X
  1070. Xwords    :        { $$ = NULL; }
  1071. X    | words word    { $$ = ($1 != NULL ? ($2 != NULL ? newnode(LAPPEND,$1,$2) : $1) : $2); }
  1072. X
  1073. X%%
  1074. X
  1075. Xvoid initparse() {
  1076. X    star = treecpy(newnode(VAR,newnode(rWORD,"*",NULL)), ealloc);
  1077. X    nolist = treecpy(newnode(VAR,newnode(rWORD,"ifs",NULL)), ealloc);
  1078. X}
  1079. END_OF_FILE
  1080.   if test 5173 -ne `wc -c <'parse.y'`; then
  1081.     echo shar: \"'parse.y'\" unpacked with wrong size!
  1082.   fi
  1083.   # end of 'parse.y'
  1084. fi
  1085. if test -f 'redir.c' -a "${1}" != "-c" ; then 
  1086.   echo shar: Will not clobber existing file \"'redir.c'\"
  1087. else
  1088.   echo shar: Extracting \"'redir.c'\" \(2480 characters\)
  1089.   sed "s/^X//" >'redir.c' <<'END_OF_FILE'
  1090. X/* redir.c: code for opening files and piping heredocs after fork but before exec. */
  1091. X
  1092. X#include "rc.h"
  1093. X#include "lex.h"
  1094. X#include "glom.h"
  1095. X#include "glob.h"
  1096. X#include "open.h"
  1097. X#include "exec.h"
  1098. X#include "utils.h"
  1099. X#include "redir.h"
  1100. X#include "hash.h"
  1101. X
  1102. X/*
  1103. X   Walk the redirection queue, and open files and dup2 to them. Also, here-documents are treated
  1104. X   here by dumping them down a pipe. (this should make here-documents fast on systems with lots
  1105. X   of memory which do pipes right. Under sh, a file is copied to /tmp, and then read out of /tmp
  1106. X   again. I'm interested in knowing how much faster, say, shar runs when unpacking when invoked
  1107. X   with rc instead of sh. On my sun4/280, it runs in about 60-75% of the time of sh for unpacking
  1108. X   the rc source distribution.)
  1109. X*/
  1110. X
  1111. Xvoid doredirs() {
  1112. X    List *fname;
  1113. X    int fd, p[2];
  1114. X    Rq *r;
  1115. X
  1116. X    for (r = redirq; r != NULL; r = r->n) {
  1117. X        switch(r->r->type) {
  1118. X        default:
  1119. X            fprint(2,"%d: bad node in doredirs\n", r->r->type);
  1120. X            exit(1);
  1121. X            /* NOTREACHED */
  1122. X        case rREDIR:
  1123. X            if (r->r->u[0].i == HERESTRING) {
  1124. X                fname = flatten(glom(r->r->u[2].p)); /* fname is really a string */
  1125. X                if (fname == NULL) {
  1126. X                    close(r->r->u[1].i); /* feature? */
  1127. X                    break;
  1128. X                }
  1129. X                if (pipe(p) < 0) {
  1130. X                    uerror("pipe");
  1131. X                    exit(1);
  1132. X                }
  1133. X                switch (fork()) {
  1134. X                case -1:
  1135. X                    uerror("fork");
  1136. X                    exit(1);
  1137. X                    /* NOTREACHED */
  1138. X                case 0:    /* child writes to pipe */
  1139. X                    setsigdefaults();
  1140. X                    close(p[0]);
  1141. X                    writeall(p[1], fname->w, strlen(fname->w));
  1142. X                    exit(0);
  1143. X                    /* NOTREACHED */
  1144. X                default:
  1145. X                    close(p[1]);
  1146. X                    if (dup2(p[0], r->r->u[1].i) < 0) {
  1147. X                        uerror("dup");
  1148. X                        exit(1);
  1149. X                    }
  1150. X                    close(p[0]);
  1151. X                }
  1152. X            } else {
  1153. X                fname = glob(glom(r->r->u[2].p));
  1154. X                if (fname == NULL) {
  1155. X                    fprint(2,"null filename in redirection\n");
  1156. X                    exit(1);
  1157. X                }
  1158. X                if (fname->n != NULL) {
  1159. X                    fprint(2,"multi-word filename in redirection\n");
  1160. X                    exit(1);
  1161. X                }
  1162. X                switch (r->r->u[0].i) {
  1163. X                default:
  1164. X                    fprint(2,"doredirs: this can't happen\n");
  1165. X                    exit(1);
  1166. X                    /* NOTREACHED */
  1167. X                case CREATE: case APPEND: case FROM:
  1168. X                    fd = rc_open(fname->w, r->r->u[0].i);
  1169. X                    break;
  1170. X                }
  1171. X                if (fd < 0) {
  1172. X                    uerror(fname->w);
  1173. X                    exit(1);
  1174. X                }
  1175. X                if (dup2(fd, r->r->u[1].i) < 0) {
  1176. X                    uerror("dup");
  1177. X                    exit(1);
  1178. X                }
  1179. X                close(fd);
  1180. X            }
  1181. X            break;
  1182. X        case rDUP:
  1183. X            if (r->r->u[2].i == -1)
  1184. X                close(r->r->u[1].i);
  1185. X            else if (dup2(r->r->u[2].i, r->r->u[1].i) < 0) {
  1186. X                uerror("dup");
  1187. X                exit(1);
  1188. X            }
  1189. X        }
  1190. X    }
  1191. X    redirq = NULL;
  1192. X}
  1193. END_OF_FILE
  1194.   if test 2480 -ne `wc -c <'redir.c'`; then
  1195.     echo shar: \"'redir.c'\" unpacked with wrong size!
  1196.   fi
  1197.   # end of 'redir.c'
  1198. fi
  1199. if test -f 'tree.c' -a "${1}" != "-c" ; then 
  1200.   echo shar: Will not clobber existing file \"'tree.c'\"
  1201. else
  1202.   echo shar: Extracting \"'tree.c'\" \(4613 characters\)
  1203.   sed "s/^X//" >'tree.c' <<'END_OF_FILE'
  1204. X/* tree.c: functions for manipulating parse-trees. (create, copy, delete) */
  1205. X
  1206. X#include <stdarg.h>
  1207. X#include "rc.h"
  1208. X#include "tree.h"
  1209. X#include "utils.h"
  1210. X#include "nalloc.h"
  1211. X
  1212. X/* make a new node, pass it back to yyparse. Used to generate the parsetree. */
  1213. X
  1214. XNode *newnode(int /*enum nodetype*/ t,...) {
  1215. X    va_list ap;
  1216. X    Node *n;
  1217. X
  1218. X    va_start(ap,t);
  1219. X
  1220. X    switch (t) {
  1221. X    default:
  1222. X        fprint(2,"newnode: this can't happen\n");
  1223. X        exit(1);
  1224. X        /* NOTREACHED */
  1225. X    case rDUP:
  1226. X        n = nalloc(offsetof(Node, u[3]));
  1227. X        n->u[0].i = va_arg(ap, int);
  1228. X        n->u[1].i = va_arg(ap, int);
  1229. X        n->u[2].i = va_arg(ap, int);
  1230. X        break;
  1231. X    case rWORD:
  1232. X        n = nalloc(offsetof(Node, u[2]));
  1233. X        n->u[0].s = va_arg(ap, char *);
  1234. X        n->u[1].s = va_arg(ap, char *);
  1235. X        break;
  1236. X    case rBANG: case NOWAIT:
  1237. X    case rCOUNT: case rFLAT: case RMFN: case rSUBSHELL:
  1238. X    case VAR:
  1239. X        n = nalloc(offsetof(Node, u[1]));
  1240. X        n->u[0].p = va_arg(ap, Node *);
  1241. X        break;
  1242. X    case rANDAND: case ASSIGN: case BACKQ: case BODY: case BRACE: case CONCAT:
  1243. X    case rELSE: case EPILOG: case rIF: case NEWFN:
  1244. X    case rOROR: case PRE: case ARGS: case rSWITCH:
  1245. X    case MATCH: case VARSUB: case rWHILE: case LAPPEND:
  1246. X        n = nalloc(offsetof(Node, u[2]));
  1247. X        n->u[0].p = va_arg(ap, Node *);
  1248. X        n->u[1].p = va_arg(ap, Node *);
  1249. X        break;
  1250. X    case FORIN:
  1251. X        n = nalloc(offsetof(Node, u[3]));
  1252. X        n->u[0].p = va_arg(ap, Node *);
  1253. X        n->u[1].p = va_arg(ap, Node *);
  1254. X        n->u[2].p = va_arg(ap, Node *);
  1255. X        break;
  1256. X    case rPIPE:
  1257. X        n = nalloc(offsetof(Node, u[4]));
  1258. X        n->u[0].i = va_arg(ap, int);
  1259. X        n->u[1].i = va_arg(ap, int);
  1260. X        n->u[2].p = va_arg(ap, Node *);
  1261. X        n->u[3].p = va_arg(ap, Node *);
  1262. X        break;
  1263. X    case rREDIR:
  1264. X    case NMPIPE:
  1265. X        n = nalloc(offsetof(Node, u[3]));
  1266. X        n->u[0].i = va_arg(ap, int);
  1267. X        n->u[1].i = va_arg(ap, int);
  1268. X        n->u[2].p = va_arg(ap, Node *);
  1269. X        break;
  1270. X     }
  1271. X    n->type = t;
  1272. X    va_end(ap);
  1273. X    return n;
  1274. X}
  1275. X
  1276. X/* copy a tree to malloc space. Used when storing the definition of a function */
  1277. X
  1278. XNode *treecpy(Node *s, void (*alloc(SIZE_T))) {
  1279. X    Node *n;
  1280. X
  1281. X    if (s == NULL)
  1282. X        return NULL;
  1283. X
  1284. X    switch (s->type) {
  1285. X    default:
  1286. X        fprint(2,"treecpy: this can't happen\n");
  1287. X        exit(1);
  1288. X        /* NOTREACHED */
  1289. X    case rDUP:
  1290. X        n = alloc(offsetof(Node, u[3]));
  1291. X        n->u[0].i = s->u[0].i;
  1292. X        n->u[1].i = s->u[1].i;
  1293. X        n->u[2].i = s->u[2].i;
  1294. X        break;
  1295. X    case rWORD:
  1296. X        n = alloc(offsetof(Node, u[2]));
  1297. X        n->u[0].s = ecpy(s->u[0].s);
  1298. X        if (s->u[1].s != NULL) {
  1299. X            SIZE_T i = strlen(s->u[0].s);
  1300. X
  1301. X            n->u[1].s = alloc(i);
  1302. X            memcpy(n->u[1].s, s->u[1].s, i);
  1303. X        } else
  1304. X            n->u[1].s = NULL;
  1305. X        break;
  1306. X    case rBANG: case NOWAIT:
  1307. X    case rCOUNT: case rFLAT: case RMFN: case rSUBSHELL: case VAR:
  1308. X        n = alloc(offsetof(Node, u[1]));
  1309. X        n->u[0].p = treecpy(s->u[0].p, alloc);
  1310. X        break;
  1311. X    case rANDAND: case ASSIGN: case BACKQ: case BODY: case BRACE: case CONCAT:
  1312. X    case rELSE: case EPILOG: case rIF: case NEWFN:
  1313. X    case rOROR: case PRE: case ARGS: case rSWITCH:
  1314. X    case MATCH: case VARSUB: case rWHILE: case LAPPEND:
  1315. X        n = alloc(offsetof(Node, u[2]));
  1316. X        n->u[0].p = treecpy(s->u[0].p, alloc);
  1317. X        n->u[1].p = treecpy(s->u[1].p, alloc);
  1318. X        break;
  1319. X    case FORIN:
  1320. X        n = alloc(offsetof(Node, u[3]));
  1321. X        n->u[0].p = treecpy(s->u[0].p, alloc);
  1322. X        n->u[1].p = treecpy(s->u[1].p, alloc);
  1323. X        n->u[2].p = treecpy(s->u[2].p, alloc);
  1324. X        break;
  1325. X    case rPIPE:
  1326. X        n = alloc(offsetof(Node, u[4]));
  1327. X        n->u[0].i = s->u[0].i;
  1328. X        n->u[1].i = s->u[1].i;
  1329. X        n->u[2].p = treecpy(s->u[2].p, alloc);
  1330. X        n->u[3].p = treecpy(s->u[3].p, alloc);
  1331. X        break;
  1332. X    case rREDIR:
  1333. X    case NMPIPE:
  1334. X        n = alloc(offsetof(Node, u[3]));
  1335. X        n->u[0].i = s->u[0].i;
  1336. X        n->u[1].i = s->u[1].i;
  1337. X        n->u[2].p = treecpy(s->u[2].p, alloc);
  1338. X        break;
  1339. X    }
  1340. X    n->type = s->type;
  1341. X    return n;
  1342. X}
  1343. X
  1344. X/* free a function definition that is no longer needed */
  1345. X
  1346. Xvoid treefree(Node *s) {
  1347. X    if (s == NULL)
  1348. X        return;
  1349. X    switch (s->type) {
  1350. X    case rDUP:
  1351. X        break;
  1352. X    case rWORD:
  1353. X        efree(s->u[0].s);
  1354. X        efree(s->u[1].s);
  1355. X        break;
  1356. X    case rBANG: case NOWAIT:
  1357. X    case rCOUNT: case rFLAT: case RMFN:
  1358. X    case rSUBSHELL: case VAR:
  1359. X        treefree(s->u[0].p);
  1360. X        efree(s->u[0].p);
  1361. X        break;
  1362. X    case rANDAND: case ASSIGN: case BACKQ: case BODY: case BRACE: case CONCAT:
  1363. X    case rELSE: case EPILOG: case rIF: case NEWFN:
  1364. X    case rOROR: case PRE: case ARGS:
  1365. X    case rSWITCH: case MATCH:  case VARSUB: case rWHILE:
  1366. X    case LAPPEND:
  1367. X        treefree(s->u[1].p);
  1368. X        treefree(s->u[0].p);
  1369. X        efree(s->u[1].p);
  1370. X        efree(s->u[0].p);
  1371. X        break;
  1372. X    case FORIN:
  1373. X        treefree(s->u[2].p);
  1374. X        treefree(s->u[1].p);
  1375. X        treefree(s->u[0].p);
  1376. X        efree(s->u[2].p);
  1377. X        efree(s->u[1].p);
  1378. X        efree(s->u[0].p);
  1379. X        break;
  1380. X    case rPIPE:
  1381. X        treefree(s->u[2].p);
  1382. X        treefree(s->u[3].p);
  1383. X        efree(s->u[2].p);
  1384. X        efree(s->u[3].p);
  1385. X        break;
  1386. X    case rREDIR:
  1387. X    case NMPIPE:
  1388. X        treefree(s->u[2].p);
  1389. X        efree(s->u[2].p);
  1390. X        break;
  1391. X    default:
  1392. X        fprint(2,"treefree: this can't happen\n");
  1393. X        exit(1);
  1394. X    }
  1395. X}
  1396. END_OF_FILE
  1397.   if test 4613 -ne `wc -c <'tree.c'`; then
  1398.     echo shar: \"'tree.c'\" unpacked with wrong size!
  1399.   fi
  1400.   # end of 'tree.c'
  1401. fi
  1402. if test -f 'utils.c' -a "${1}" != "-c" ; then 
  1403.   echo shar: Will not clobber existing file \"'utils.c'\"
  1404. else
  1405.   echo shar: Extracting \"'utils.c'\" \(5186 characters\)
  1406.   sed "s/^X//" >'utils.c' <<'END_OF_FILE'
  1407. X/* utils.c: general utility functions like fprint, ealloc etc. */
  1408. X
  1409. X#include <stdarg.h>
  1410. X#include <errno.h>
  1411. X#include <setjmp.h>
  1412. X#include <signal.h>
  1413. X#include "rc.h"
  1414. X#include "utils.h"
  1415. X#include "nalloc.h"
  1416. X#include "status.h"
  1417. X#include "input.h"
  1418. X#include "except.h"
  1419. X#include "lex.h"    /* import char nw[]; used by strprint to see if it needs to quote a word */
  1420. X#include "walk.h"
  1421. X
  1422. Xstatic void dprint(va_list, char *, char *);
  1423. Xstatic int n2u(char *, int);
  1424. X
  1425. X/* exception handlers */
  1426. X
  1427. Xvoid rc_error(char *s) {
  1428. X    if (s != NULL) {
  1429. X        if (interactive)
  1430. X            fprint(2,"%s\n",s);
  1431. X        else
  1432. X            fprint(2,"line %d: %s\n", lineno - 1, s);
  1433. X    }
  1434. X    set(FALSE);
  1435. X    redirq = NULL;
  1436. X    cond = FALSE; /* no longer inside conditional */
  1437. X    empty_fifoq();
  1438. X    rc_raise(ERROR);
  1439. X}
  1440. X
  1441. Xvoid sig(int s) {
  1442. X    signal(SIGINT, sig); /* some unices require re-signaling */
  1443. X
  1444. X    if (errno == EINTR)
  1445. X        return; /* allow wait() to complete */
  1446. X
  1447. X    fprint(2,"\n"); /* this is the newline you see when you hit ^C while typing a command */
  1448. X    redirq = NULL;
  1449. X    cond = FALSE;
  1450. X    empty_fifoq();
  1451. X    rc_raise(ERROR);
  1452. X}
  1453. X
  1454. X/* our perror */
  1455. X
  1456. Xvoid uerror(char *s) {
  1457. X    extern int sys_nerr;
  1458. X    extern char *sys_errlist[];
  1459. X
  1460. X    if (errno > sys_nerr)
  1461. X        return;
  1462. X
  1463. X    if (s != NULL)
  1464. X        fprint(2,"%s: %s\n",s,sys_errlist[errno]);
  1465. X    else
  1466. X        fprint(2,"%s\n",sys_errlist[errno]);
  1467. X}
  1468. X
  1469. X/* printing functions */
  1470. X
  1471. Xvoid fprint(int fd, char *f,...) {
  1472. X        va_list ap;
  1473. X    char str[FPRINT_SIZE];
  1474. X
  1475. X    va_start(ap,f);
  1476. X    dprint(ap, str, f);
  1477. X    va_end(ap);
  1478. X    writeall(fd,str,strlen(str));
  1479. X}
  1480. X
  1481. Xchar *sprint(char *b, char *f,...) {
  1482. X    va_list ap;
  1483. X
  1484. X    va_start(ap, f);
  1485. X    dprint(ap, b, f);
  1486. X    va_end(ap);
  1487. X    return b;
  1488. X}
  1489. X
  1490. Xstatic void dprint(va_list ap, char *strbuf, char *f) {
  1491. X    int i;
  1492. X
  1493. X    for (i = 0; *f != '\0'; f++) {
  1494. X        if (*f != '%') {
  1495. X            strbuf[i++] = *f;
  1496. X            continue; /* avoid an ugly extra level of indentation */
  1497. X        }
  1498. X        switch (*++f) {
  1499. X        case 'a': {
  1500. X            char **a = va_arg(ap, char **);
  1501. X
  1502. X            if (*a == NULL)
  1503. X                break;
  1504. X            strcpy(strbuf + i, *a);
  1505. X            i += strlen(*a);
  1506. X            while (*++a != NULL) {
  1507. X                strbuf[i++] = ' ';
  1508. X                strcpy(strbuf + i, *a);
  1509. X                i += strlen(*a);
  1510. X            }
  1511. X            break;
  1512. X        }
  1513. X        case 'c':
  1514. X            strbuf[i++] = va_arg(ap, int);
  1515. X            break;
  1516. X        case 'd': case 'o': {
  1517. X            int v = va_arg(ap, int);
  1518. X            int j = 0;
  1519. X            int base = (*f == 'd' ? 10 : 8);
  1520. X            char num[16];
  1521. X
  1522. X            if (v == 0)
  1523. X                num[j++] = '0';
  1524. X            while (v != 0) {
  1525. X                num[j++] = (v % base) + '0';
  1526. X                v /= base;
  1527. X            }
  1528. X            while (--j >= 0)
  1529. X                strbuf[i++] = num[j];
  1530. X            break;
  1531. X        }
  1532. X        case 's': {
  1533. X            char *s = va_arg(ap, char *);
  1534. X            while (*s != '\0')
  1535. X                strbuf[i++] = *s++;
  1536. X                break;
  1537. X        }
  1538. X        default: /* on format error, just print the bad format */
  1539. X            strbuf[i++] = '%';
  1540. X            /* FALLTHROUGH */
  1541. X        case '%':
  1542. X            strbuf[i++] = *f;
  1543. X        }
  1544. X    }
  1545. X    strbuf[i] = '\0';
  1546. X}
  1547. X
  1548. X/* prints a string in rc-quoted form. e.g., a string with spaces in it must be quoted */
  1549. X
  1550. Xchar *strprint(char *s, int quotable, int metaquote) { /* really boolean, but y.tab.c includes utils.h */
  1551. X    SIZE_T i,j;
  1552. X    char *t;
  1553. X
  1554. X    if (*s == '\0')
  1555. X        return "''";
  1556. X
  1557. X    for (i = 0; s[i] != '\0'; i++)
  1558. X        if (nw[s[i]] == 1 && (metaquote || (s[i] != '*' && s[i] != '?' && s[i] != '[')))
  1559. X            quotable = TRUE;
  1560. X
  1561. X    if (!quotable)
  1562. X        return s;
  1563. X
  1564. X    for(i = j = 0; s[i] != '\0'; i++, j++)
  1565. X        if (s[i] == '\'')
  1566. X            j++;
  1567. X
  1568. X    t = nalloc(j + 3);
  1569. X
  1570. X    t[0] = '\'';
  1571. X
  1572. X    for (j = 1, i = 0; s[i] != '\0'; i++, j++) {
  1573. X        t[j] = s[i];
  1574. X        if (s[i] == '\'')
  1575. X            t[++j] = '\'';
  1576. X    }
  1577. X
  1578. X    t[j++] = '\'';
  1579. X    t[j] = '\0';
  1580. X
  1581. X    return t;
  1582. X}
  1583. X
  1584. X/* ascii -> unsigned conversion routines. -1 indicates conversion error. */
  1585. X
  1586. Xstatic int n2u(char *s, int base) {
  1587. X    int i;
  1588. X
  1589. X    for (i = 0; *s != '\0'; s++) {
  1590. X        /* small hack with unsigned ints -- one compare for range test */
  1591. X        if (((unsigned int) *s) - '0' >= (unsigned int) base)
  1592. X            return -1;
  1593. X        i = (i * base) + (*s - '0');
  1594. X    }
  1595. X    return i;
  1596. X}
  1597. X
  1598. X/* decimal -> uint */
  1599. X
  1600. Xint a2u(char *s) {
  1601. X    return n2u(s, 10);
  1602. X}
  1603. X
  1604. X/* octal -> uint */
  1605. X
  1606. Xint o2u(char *s) {
  1607. X    return n2u(s, 8);
  1608. X}
  1609. X
  1610. X/* memory allocation functions */
  1611. X
  1612. Xvoid *ealloc(SIZE_T n) {
  1613. X    char *p = malloc(n);
  1614. X
  1615. X    if (p == NULL) {
  1616. X        uerror("malloc");
  1617. X        rc_exit(1);
  1618. X    }
  1619. X
  1620. X    return p;
  1621. X}
  1622. X
  1623. Xvoid *erealloc(void *p, SIZE_T n) {
  1624. X    p = realloc(p, n);
  1625. X
  1626. X    if (p == NULL) {
  1627. X        uerror("realloc");
  1628. X        rc_exit(1);
  1629. X    }
  1630. X
  1631. X    return p;
  1632. X}
  1633. X
  1634. Xvoid efree(void *p) {
  1635. X    if (p != NULL)
  1636. X        free(p);
  1637. X}
  1638. X
  1639. X/* useful functions */
  1640. X
  1641. X/* The last word in portable ANSI: a strcmp wrapper for qsort */
  1642. X
  1643. Xint starstrcmp(const void *s1, const void *s2) {
  1644. X    return strcmp(*(char **)s1, *(char **)s2);
  1645. X}
  1646. X
  1647. X/* tests to see if pathname begins with "/", "./", or "../" */
  1648. X
  1649. Xint isabsolute(char *path) {
  1650. X    return path[0] == '/' || (path[0] == '.' && (path[1] == '/' || (path[1] == '.' && path[2] == '/')));
  1651. X}
  1652. X
  1653. X/* write a given buffer allowing for partial writes from write(2) */
  1654. X
  1655. Xvoid writeall(int fd, char *buf, SIZE_T remain) {
  1656. X    int i;
  1657. X
  1658. X    for (i = 0; remain > 0; buf += i, remain -= i)
  1659. X        i = write(fd, buf, remain);
  1660. X}
  1661. X
  1662. X/* clear out z bytes from character string s */
  1663. X
  1664. Xvoid clear(char *s, SIZE_T z) {
  1665. X    while (z != 0)
  1666. X        s[--z] = 0;
  1667. X}
  1668. X
  1669. X/* zero out the fifo queue, removing the fifos from /tmp as you go (also prints errors arising from signals) */
  1670. X
  1671. Xvoid empty_fifoq() {
  1672. X    int sp;
  1673. X
  1674. X    while (fifoq != NULL) {
  1675. X        unlink(fifoq->w);
  1676. X        wait(&sp);
  1677. X        statprint(sp);
  1678. X        fifoq = fifoq->n;
  1679. X    }
  1680. X}
  1681. X
  1682. XSIZE_T strarraylen(char **a) {
  1683. X    SIZE_T i;
  1684. X
  1685. X    for (i = 0; *a != NULL; a++)
  1686. X        i += strlen(*a) + 1;
  1687. X
  1688. X    return i;
  1689. X}
  1690. END_OF_FILE
  1691.   if test 5186 -ne `wc -c <'utils.c'`; then
  1692.     echo shar: \"'utils.c'\" unpacked with wrong size!
  1693.   fi
  1694.   # end of 'utils.c'
  1695. fi
  1696. if test -f 'var.c' -a "${1}" != "-c" ; then 
  1697.   echo shar: Will not clobber existing file \"'var.c'\"
  1698. else
  1699.   echo shar: Extracting \"'var.c'\" \(5802 characters\)
  1700.   sed "s/^X//" >'var.c' <<'END_OF_FILE'
  1701. X/* var.c: provide "public" functions for adding and removing variables from the symbol table */
  1702. X
  1703. X#include "rc.h"
  1704. X#include "utils.h"
  1705. X#include "hash.h"
  1706. X#include "list.h"
  1707. X#include "footobar.h"
  1708. X#include "nalloc.h"
  1709. X#include "status.h"
  1710. X#include "glom.h"
  1711. X
  1712. X#ifdef READLINE /* need to reset readline() every time TERM or TERMCAP changes */
  1713. Xextern void rl_reset_terminal(char *);
  1714. X#endif
  1715. X
  1716. Xstatic void colonassign(char *, List *, boolean);
  1717. Xstatic void listassign(char *, List *, boolean);
  1718. Xstatic int hasalias(char *);
  1719. X
  1720. Xstatic char *const aliases[] = {
  1721. X    "home", "HOME", "path", "PATH", "cdpath", "CDPATH"
  1722. X};
  1723. X
  1724. X/* assign a variable in List form to a name, stacking if appropriate */
  1725. X
  1726. Xvoid varassign(char *name, List *def, boolean stack) {
  1727. X    Variable *new;
  1728. X    List *newdef = listcpy(def); /* important to do the listcpy first; get_var_place() frees old values */
  1729. X
  1730. X    new = get_var_place(name, stack);
  1731. X    new->def = newdef;
  1732. X    new->extdef = NULL;
  1733. X
  1734. X#ifdef READLINE /* need to reset readline() every time TERM or TERMCAP changes */
  1735. X    if (interactive && streq(name, "TERM") || streq(name, "TERMCAP"))
  1736. X        rl_reset_terminal(NULL);
  1737. X#endif
  1738. X}
  1739. X
  1740. X/* assign a variable in string form. Check to see if it is aliased (e.g., PATH and path) */
  1741. X
  1742. Xboolean varassign_string(char *extdef) {
  1743. X    char *name = get_name(extdef);
  1744. X    Variable *new;
  1745. X    int i;
  1746. X    static boolean aliasset[arraysize(aliases)] = {
  1747. X        FALSE, FALSE, FALSE, FALSE, FALSE, FALSE
  1748. X    };
  1749. X
  1750. X    if (name == NULL)
  1751. X        return FALSE; /* add it to bozo env */
  1752. X
  1753. X    i = hasalias(name);
  1754. X    if (i >= 0) {
  1755. X        aliasset[i] = TRUE;
  1756. X        if ((i & 1 == 0) && aliasset[i^1])
  1757. X            return TRUE; /* don't alias variables that are already set in upper case */
  1758. X    }
  1759. X    new = get_var_place(name, FALSE);
  1760. X    new->def = NULL;
  1761. X    new->extdef = ealloc(strlen(extdef) + 1);
  1762. X    strcpy(new->extdef, extdef);
  1763. X    if (hasalias(name) != -1)
  1764. X        alias(name, varlookup(name), FALSE);
  1765. X    return TRUE;
  1766. X}
  1767. X
  1768. X/*
  1769. X   Return a List based on a name lookup. If the list is in external (string) form,
  1770. X   convert it to internal (List) form. Treat $n (n is an integer) specially as $*(n).
  1771. X   Also check to see if $status is being dereferenced. (we lazily evaluate the List
  1772. X   associated with $status)
  1773. X*/
  1774. X
  1775. XList *varlookup(char *name) {
  1776. X    Variable *look;
  1777. X    List *ret, *l;
  1778. X    int sub;
  1779. X
  1780. X    if (streq(name, "status"))
  1781. X        return sgetstatus();
  1782. X
  1783. X    if (*name != '\0' && (sub = a2u(name)) != -1) { /* handle $1, $2, etc. */
  1784. X        for (l = varlookup("*"); l != NULL && sub != 0; --sub)
  1785. X            l = l->n;
  1786. X        if (l == NULL)
  1787. X            return NULL;
  1788. X        ret = nnew(List);
  1789. X        ret->w = l->w;
  1790. X        ret->m = NULL;
  1791. X        ret->n = NULL;
  1792. X        return ret;
  1793. X    }
  1794. X
  1795. X    look = lookup_var(name);
  1796. X
  1797. X    if (look == NULL)
  1798. X        return NULL; /* not found */
  1799. X    if (look->def != NULL)
  1800. X        return look->def;
  1801. X    if (look->extdef == NULL)
  1802. X        return NULL; /* variable was set to null, e.g., a=() echo foo */
  1803. X
  1804. X    ret = parse_var(name, look->extdef);
  1805. X
  1806. X    if (ret == NULL) {
  1807. X        look->extdef = NULL;
  1808. X        return NULL;
  1809. X    }
  1810. X    return look->def = ret;
  1811. X}
  1812. X
  1813. X/* lookup a variable in external (string) form, converting if necessary. Used by makeenv() */
  1814. X
  1815. Xchar *varlookup_string(char *name) {
  1816. X    Variable *look;
  1817. X
  1818. X    look = lookup_var(name);
  1819. X
  1820. X    if (look == NULL)
  1821. X        return NULL;
  1822. X    if (look->extdef != NULL)
  1823. X        return look->extdef;
  1824. X    if (look->def == NULL)
  1825. X        return NULL;
  1826. X    return look->extdef = list2str(name, look->def);
  1827. X}
  1828. X
  1829. X/* remove a variable from the symtab. "stack" determines whether a level of scoping is popped or not */
  1830. X
  1831. Xvoid varrm(char *name, boolean stack) {
  1832. X    int i = hasalias(name);
  1833. X
  1834. X    if (streq(name, "*") && !stack) { /* when assigning () to $*, we want to preserve $0 */
  1835. X        varassign("*", varlookup("0"), FALSE);
  1836. X        return;
  1837. X    }
  1838. X        
  1839. X    delete_var(name, stack);
  1840. X    if (i != -1)
  1841. X        delete_var(aliases[i^1], stack);
  1842. X}
  1843. X
  1844. X/* assign a value (List) to a variable, using array "a" as input. Used to assign $* */
  1845. X
  1846. Xvoid starassign(char *dollarzero, char **a, boolean stack) {
  1847. X    List *s, *var;
  1848. X
  1849. X    var = nnew(List);
  1850. X    var->w = dollarzero;
  1851. X
  1852. X    if (*a == NULL) {
  1853. X        var->n = NULL;
  1854. X        varassign("*", var, stack);
  1855. X        return;
  1856. X    }
  1857. X
  1858. X    var->n = s = nnew(List);
  1859. X
  1860. X    while (1) {
  1861. X        s->w = *a++;
  1862. X        if (*a == NULL) {
  1863. X            s->n = NULL;
  1864. X            break;
  1865. X        } else {
  1866. X            s->n = nnew(List);
  1867. X            s = s->n;
  1868. X        }
  1869. X    }
  1870. X    varassign("*", var, stack);
  1871. X}
  1872. X
  1873. X/* (ugly name, huh?) assign a colon-separated value to a variable (e.g., PATH) from a List (e.g., path) */
  1874. X
  1875. Xstatic void colonassign(char *name, List *def, boolean stack) {
  1876. X    char *colondef;
  1877. X    List dud;
  1878. X    SIZE_T deflen;
  1879. X    List *r;
  1880. X
  1881. X    if (def == NULL) {
  1882. X        varassign(name, NULL, stack);
  1883. X        return;
  1884. X    }
  1885. X
  1886. X    deflen = listlen(def) + 1; /* one for the null terminator */
  1887. X
  1888. X    colondef = nalloc(deflen);
  1889. X    strcpy(colondef, def->w);
  1890. X
  1891. X    for (r = def->n; r != NULL; r = r->n) {
  1892. X        strcat(colondef, ":");
  1893. X        strcat(colondef, r->w);
  1894. X    }
  1895. X
  1896. X    dud.w = colondef;
  1897. X    dud.n = NULL;
  1898. X    varassign(name, &dud, stack);
  1899. X}
  1900. X
  1901. X/* assign a List variable (e.g., path) from a colon-separated string (e.g., PATH) */
  1902. X
  1903. Xstatic void listassign(char *name, List *def, boolean stack) {
  1904. X    List *val, *r;
  1905. X    char *v, *w;
  1906. X
  1907. X    if (def == NULL) {
  1908. X        varassign(name, NULL, stack);
  1909. X        return;
  1910. X    }
  1911. X
  1912. X    v = def->w;
  1913. X
  1914. X    r = val = enew(List);
  1915. X
  1916. X    while((w = strchr(v,':')) != NULL) {
  1917. X        *w = '\0';
  1918. X        r->w = ecpy(v);
  1919. X        *w = ':';
  1920. X        v = w + 1;
  1921. X        r->n = enew(List);
  1922. X        r = r->n;
  1923. X    }
  1924. X    r->w = ecpy(v);
  1925. X    r->n = NULL;
  1926. X
  1927. X    varassign(name, val, stack);
  1928. X}
  1929. X
  1930. X/* check to see if a particular variable is aliased; return -1 on failure, or the index */
  1931. X
  1932. Xstatic int hasalias(char *name) {
  1933. X    int i;
  1934. X
  1935. X    for (i = 0; i < arraysize(aliases); i++)
  1936. X        if (streq(name, aliases[i]))
  1937. X            return i;
  1938. X    return -1;
  1939. X}
  1940. X
  1941. X/* alias a variable to its lowercase equivalent. function pointers are used to specify the conversion function */
  1942. X
  1943. Xvoid alias(char *name, List *s, boolean stack) {
  1944. X    int i = hasalias(name);
  1945. X    static void (*vectors[])(char *, List *, boolean) = {
  1946. X        varassign, varassign, colonassign, listassign, colonassign, listassign
  1947. X    };
  1948. X
  1949. X    if (i != -1)
  1950. X        vectors[i](aliases[i^1], s, stack); /* xor hack to reverse case of alias entry */
  1951. X}
  1952. END_OF_FILE
  1953.   if test 5802 -ne `wc -c <'var.c'`; then
  1954.     echo shar: \"'var.c'\" unpacked with wrong size!
  1955.   fi
  1956.   # end of 'var.c'
  1957. fi
  1958. if test -f 'which.c' -a "${1}" != "-c" ; then 
  1959.   echo shar: Will not clobber existing file \"'which.c'\"
  1960. else
  1961.   echo shar: Extracting \"'which.c'\" \(2968 characters\)
  1962.   sed "s/^X//" >'which.c' <<'END_OF_FILE'
  1963. X/* which.c: check to see if a file is executable.
  1964. X
  1965. X   This function is isolated from the rest because of #include trouble with
  1966. X   ANSI compilers.
  1967. X
  1968. X   This function was originally written with Maarten Litmaath's which.c as
  1969. X   a template, but was changed in order to accomodate the possibility of
  1970. X   rc's running setuid or the possibility of executing files not in the
  1971. X   primary group. Much of this file has been re-vamped by Paul Haahr.
  1972. X   I re-re-vamped the functions that Paul supplied to correct minor bugs
  1973. X   and to strip out unneeded functionality.
  1974. X*/
  1975. X
  1976. X#include <sys/types.h>
  1977. X#include <sys/stat.h>
  1978. X#include <sys/param.h>
  1979. X#include "builtins.h"
  1980. X
  1981. X#define M_USR 0700
  1982. X#define M_GRP 0070
  1983. X#define M_OTH 0007
  1984. X#define X_ALL 0111
  1985. X
  1986. X#ifndef NULL
  1987. X#define NULL 0
  1988. X#endif
  1989. X
  1990. Xtypedef struct List {
  1991. X    char *w;
  1992. X    char *m;
  1993. X    struct List *n;
  1994. X} List;
  1995. X
  1996. Xextern int stat(const char *, struct stat *);
  1997. Xextern int geteuid(void);
  1998. Xextern int getegid(void);
  1999. Xextern int getgroups(int, int *);
  2000. Xextern char *strcpy(char *, char *);
  2001. Xextern char *strcat(char *, char *);
  2002. Xextern int strlen(char *);
  2003. X
  2004. Xextern List *varlookup(char *);
  2005. Xextern void *ealloc(int);
  2006. Xextern void efree(void *);
  2007. Xextern int isabsolute(char *);
  2008. X
  2009. Xstatic int initialized = 0;
  2010. Xstatic int uid, gid;
  2011. X
  2012. X#ifdef NGROUPS
  2013. Xstatic int ngroups, gidset[NGROUPS];
  2014. X
  2015. X/* determine whether gid lies in gidset */
  2016. X
  2017. Xstatic int ingidset(int gid) {
  2018. X    int i;
  2019. X    for (i = 0; i < ngroups; i++)
  2020. X        if (gid == gidset[i])
  2021. X            return 1;
  2022. X    return 0;
  2023. X}
  2024. X#endif
  2025. X
  2026. X/*
  2027. X   A home-grown access/stat. Does the right thing for group-executable files.
  2028. X   Returns a boolean result instead of this -1 nonsense.
  2029. X*/
  2030. X
  2031. Xstatic int rc_access(char *path) {
  2032. X    struct stat st;
  2033. X    int mask;
  2034. X
  2035. X    if (stat(path, &st) != 0)
  2036. X        return 0;
  2037. X
  2038. X    mask = X_ALL;
  2039. X
  2040. X    if (uid != 0) {
  2041. X        if (uid == st.st_uid)
  2042. X            mask &= M_USR;
  2043. X#ifdef NGROUPS
  2044. X        else if (gid == st.st_gid || ingidset(st.st_gid))
  2045. X#else
  2046. X        else if (gid == st.st_gid)
  2047. X#endif
  2048. X            mask &= M_GRP;
  2049. X        else
  2050. X            mask &= M_OTH;
  2051. X    }
  2052. X    
  2053. X    return (st.st_mode & S_IFMT) == S_IFREG && (st.st_mode & mask) == mask;
  2054. X}
  2055. X
  2056. X/* return a full pathname by searching $path, and by checking the status of the file */
  2057. X
  2058. Xchar *which(char *name) {
  2059. X    static char *test = NULL;
  2060. X    static int testlen = 0;
  2061. X    List *path;
  2062. X    int len;
  2063. X
  2064. X    if (name == NULL)    /* no filename? can happen with "> foo" as a command */
  2065. X        return NULL;
  2066. X
  2067. X    if (!initialized) {
  2068. X        initialized = 1;
  2069. X        uid = geteuid();
  2070. X        gid = getegid();
  2071. X#ifdef NGROUPS
  2072. X        ngroups = getgroups(NGROUPS, gidset);
  2073. X#endif
  2074. X    }
  2075. X
  2076. X    if (isabsolute(name)) /* absolute pathname? */
  2077. X        return rc_access(name) ? name : NULL;
  2078. X
  2079. X    len = strlen(name);
  2080. X    for (path = varlookup("path"); path != NULL; path = path->n) {
  2081. X        int need = strlen(path->w) + len + 2; /* one for null terminator, one for the '/' */
  2082. X        if (testlen < need) {
  2083. X            efree(test);
  2084. X            test = ealloc(testlen = need);
  2085. X        }
  2086. X        if (*path->w == '\0') {
  2087. X            strcpy(test, name);
  2088. X        } else {
  2089. X            strcpy(test, path->w);
  2090. X            strcat(test, "/");
  2091. X            strcat(test, name);
  2092. X        }
  2093. X        if (rc_access(test))
  2094. X            return test;
  2095. X    }
  2096. X    return NULL;
  2097. X}
  2098. END_OF_FILE
  2099.   if test 2968 -ne `wc -c <'which.c'`; then
  2100.     echo shar: \"'which.c'\" unpacked with wrong size!
  2101.   fi
  2102.   # end of 'which.c'
  2103. fi
  2104. echo shar: End of archive 3 \(of 4\).
  2105. cp /dev/null ark3isdone
  2106. MISSING=""
  2107. for I in 1 2 3 4 ; do
  2108.     if test ! -f ark${I}isdone ; then
  2109.     MISSING="${MISSING} ${I}"
  2110.     fi
  2111. done
  2112. if test "${MISSING}" = "" ; then
  2113.     echo You have unpacked all 4 archives.
  2114.     rm -f ark[1-9]isdone
  2115. else
  2116.     echo You still must unpack the following archives:
  2117.     echo "        " ${MISSING}
  2118. fi
  2119. exit 0
  2120. exit 0 # Just in case...
  2121. -- 
  2122. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  2123. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  2124. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  2125. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  2126.